/**
 * Promise.prototype.then()是为期约实例添加处理程序的主要方法。
 * 这个新期约实例基于 onResovled 处理程序的返回值构建。
 * 换句话说，该处理程序的返回值会通过 Promise.resolve()包装来生成新期约。
 * 如果没有提供这个处理程序，则 Promise.resolve()就会包装上一个期约解决之后的值。
 * 如果没有显式的返回语句，则 Promise.resolve()会包装默认的返回值 undefined。
 */
;(function () {

    let p1 = Promise.resolve('foo')
    setTimeout(console.log, 0, p1)

    // 若调用 then()时不传处理程序，则原样向后传
    let p2 = p1.then()
    setTimeout(console.log, 0, p2)  // Promise { 'foo' }

    // 这些都一样
    let p3 = p1.then(() => undefined)
    let p4 = p1.then(() => {
    })
    let p5 = p1.then(() => Promise.resolve())

    setTimeout(console.log, 0, p3); // Promise <resolved>: undefined
    setTimeout(console.log, 0, p4); // Promise <resolved>: undefined
    setTimeout(console.log, 0, p5); // Promise <resolved>: undefined

    // 如果有显式的返回值，则 Promise.resolve()会包装这个值
    let p6 = p1.then(() => 'bar')
    let p7 = p1.then(() => Promise.resolve('bar'))

    setTimeout(console.log, 0, p6); // Promise <resolved>: bar
    setTimeout(console.log, 0, p7); // Promise <resolved>: bar

    // Promise.resolve()保留返回的期约
    let p8 = p1.then(() => new Promise(() => {
    }))
    // let p9 = p1.then(() => Promise.reject())

    setTimeout(console.log, 0, p8); // Promise <pending>
    // setTimeout(console.log, 0, p9); // Promise <rejected>: undefined

    // 抛出异常会返回拒绝的期约
    // let p10 = p1.then(()=>{throw 'baz'})
    // setTimeout(console.log, 0, p10); // Promise <rejected> baz

    // 注意，返回错误值不会触发上面的拒绝行为，而会把错误对象包装在一个解决的期约中
    let p11 = p1.then(() => Error('qux'))
    setTimeout(console.log, 0, p11); // Promise <resolved>: Error: qux
    setTimeout(console.log, 0, "================")
})()

/**
 * 传递解决值和拒绝理由
 */
;(function () {
    // 在执行函数中，解决的值和拒绝的理由是分别作为 resolve()和 reject()的第一个参数往后传
    // 的。然后，这些值又会传给它们各自的处理程序，作为 onResolved 或 onRejected 处理程序的唯一参数。
    let p1 = new Promise((resolve, reject) => resolve('foo'))
    p1.then((value) => console.log(value + "11")) // foo

    let p2 = new Promise((resolve, reject) => reject('bar'))
    p2.catch((reason) => console.log(reason + "22"))

    // Promise.resolve()和 Promise.reject()在被调用时就会接收解决值和拒绝理由。同样地，它
    // 们返回的期约也会像执行器一样把这些值传给 onResolved 或 onRejected 处理程序：

    let p3 = Promise.resolve('foo')
    p3.then((value) => console.log(value + "33")) // foo

    let p4 = Promise.reject('bar')
    p4.catch((reason) => console.log(reason + "44")) // foo

})()

/**
 * 拒绝期约与拒绝错误处理拒绝期约类似于 throw()表达式，因为它们都代表一种程序状态，即需要中断或者特殊处理。在期
 * 约的执行函数或处理程序中抛出错误会导致拒绝，对应的错误对象会成为拒绝的理由。
 */
;(function () {

    // let p1 = new Promise((resolve, reject) => reject(Error('foo')))
    // let p2 = new Promise((resolve, reject) => {
    //     throw Error('foo')
    // }).catch((reason=>console.log(reason)))
    let p3 = Promise.resolve().then(() => {
        throw Error('foo')
    })
    let p4 = Promise.reject(Error('foo'))
    // setTimeout(console.log, 0, p1); // Promise <rejected>: Error: foo
    // setTimeout(console.log, 0, p2); // Promise <rejected>: Error: foo
    setTimeout(console.log, 0, p3); // Promise <rejected>: Error: foo
    setTimeout(console.log, 0, p4); // Promise <rejected>: Error: foo
})()
